﻿//  --------------------------------
//  Copyright (c) Shawn Duggan. All rights reserved.
//  This source code is made available under the terms of the Microsoft Public License (Ms-PL)
//  http://www.opensource.org/licenses/ms-pl.html
//  ---------------------------------

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;

// Taken from the BlueTango library from Shawn Duggan, http://www.shawnduggan.com/?p=54
// original namespace is BlueTango.WPFControls
namespace Elca.MvvmHelpers
{
    /// <summary>
    /// Represents a bindable rich editing control which operates on System.Windows.Documents.FlowDocument
    /// objects.    
    /// </summary>
    public class BindableRichTextBox : RichTextBox
    {
        /// <summary>
        /// Identifies the <see cref="Document"/> dependency property.
        /// </summary>
        public static readonly DependencyProperty DocumentProperty =
            DependencyProperty.Register("Document", typeof(FlowDocument), typeof(BindableRichTextBox),
            new FrameworkPropertyMetadata(null,
                    FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                    new PropertyChangedCallback(Document_PropertyChanged)));

        /// <summary>
        /// Initializes a new instance of the <see cref="BindableRichTextBox"/> class.
        /// </summary>
        public BindableRichTextBox() {
            LostFocus += BindableRichTextBox_LostFocus;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="BindableRichTextBox"/> class.
        /// </summary>
        /// <param title="document">A <see cref="T:System.Windows.Documents.FlowDocument"></see> to be added as the initial contents of the new <see cref="T:System.Windows.Controls.BindableRichTextBox"></see>.</param>
        public BindableRichTextBox(FlowDocument document) : base(document) { }

        /// <summary>
        /// Gets or sets the <see cref="T:System.Windows.Documents.FlowDocument"></see> that represents the contents of 
        /// the <see cref="T:System.Windows.Controls.BindableRichTextBox"></see>.
        /// </summary>
        /// <value></value>
        /// <returns>A <see cref="T:System.Windows.Documents.FlowDocument"></see> object that represents the contents of 
        /// the <see cref="T:System.Windows.Controls.BindableRichTextBox"></see>.By default, this property is set to an 
        /// empty <see cref="T:System.Windows.Documents.FlowDocument"></see>.  Specifically, the empty 
        /// <see cref="T:System.Windows.Documents.FlowDocument"></see> contains a single 
        /// <see cref="T:System.Windows.Documents.Paragraph"></see>, which contains a single 
        /// <see cref="T:System.Windows.Documents.Run"></see> which contains no text.</returns>
        /// <exception cref="T:System.ArgumentException">Raised if an attempt is made to set this property to a 
        /// <see cref="T:System.Windows.Documents.FlowDocument"></see> that represents the contents of another 
        /// <see cref="T:System.Windows.Controls.RichTextBox"></see>.</exception>
        /// <exception cref="T:System.ArgumentNullException">Raised if an attempt is made to set this property to null.</exception>
        /// <exception cref="T:System.InvalidOperationException">Raised if this property is set while a change block has been activated.</exception>
        public new FlowDocument Document
        {
            get { return (FlowDocument) GetValue(DocumentProperty); }
            set { SetValue(DocumentProperty, value); }
        }

        private static void Document_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
            BindableRichTextBox b = (BindableRichTextBox)d;
            b.UpdateBaseDocument();
        }

        private void UpdateBaseDocument() {
            base.Document = (FlowDocument)GetValue(DocumentProperty);
        }

        /// <summary>
        /// Handles the LostFocus event of the BindableRichTextBox control.
        /// </summary>
        /// <param title="sender">The source of the event.</param>
        /// <param title="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void BindableRichTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            // If we have a binding that is set for LostFocus or Default (which we are specifying as default)
            // then update the source.
            var binding = BindingOperations.GetBinding(this, DocumentProperty);

            if (binding.UpdateSourceTrigger == UpdateSourceTrigger.Default || binding.UpdateSourceTrigger == UpdateSourceTrigger.LostFocus)
            {
                BindingOperations.GetBindingExpression(this, DocumentProperty).UpdateSource();
            }
        }
    }
}